\documentclass[11pt, a4paper]{article}

% Configuración de márgenes de las páginas
	\usepackage{a4wide}

% Paquete de acentos para Linux
	\usepackage[utf8]{inputenc}

% Paquete para reconocer la separación en sílabas en español
	\usepackage[spanish]{babel}

% Paquetes especiales para el TP
	\usepackage{./otros/caratula}
	\usepackage{pdfpages}

% Paquete para incluir hypervinculos
	\usepackage{color}
	\usepackage{url}
	\definecolor{lnk}{rgb}{0,0,0.4}
	\usepackage[colorlinks=true,linkcolor=lnk,citecolor=blue,urlcolor=blue]{hyperref}

% Paquete para armar índices
	\usepackage{makeidx}
	\makeindex

% Más espacio entre líneas
	\parskip=1.5pt

% Opciones de enumerates
	\usepackage{enumerate}

% Para source code listings en C
	\usepackage{listings}
	\usepackage{amssymb}
	\lstset{language=C,basicstyle=\small\tt,keywordstyle=\bf,tabsize=3,breaklines=true,linewidth=16cm,postbreak={\mbox{$\rightsquigarrow$}},prebreak={\mbox{$\rightsquigarrow$}}}

\begin{document}

% Carátula
	\titulo{Primer Trabajo Práctico}
	\fecha{29 de Junio de 2010}
	\materia{Sistemas Operativos}
	\integrante{Allekotte, Kevin}{490/08}{kevinalle@gmail.com}
	\integrante{Castellano, Ezequiel}{161/08}{ezequiel.castellano@gmail.com}
	\integrante{Di Pietro, Carlos Augusto Lyon}{126/08}{cdipietro@dc.uba.ar}
	\maketitle

% Índice
\newpage \printindex \tableofcontents

% Cuerpo del informe

\setcounter{section}{2}
\begin{section}{Respuestas}

	\begin{subsection}{Comandos básicos de Unix}

		%Ej 3.1.1
		\begin{subsubsection}{pwd}
			\begin{itemize}
				\item[a] El directorio actual pasa a ser \texttt{/usr/bin}.
				\item[b] El directorio actual pasa a ser el home del usuario actual (\texttt{/home/tp}).
				\item[c] Si el comando \texttt{cd} no tiene parámetros, cambia el directorio actual a \texttt{\$HOME}, el home del usuario actual.
			\end{itemize}
		\end{subsubsection}

		%Ej 3.1.2
		\begin{subsubsection}{cat}
		Con \texttt{cat .profile} podemos ver que el contenido del archivo \texttt{/home/tp/.profile} es el siguiente:
\begin{lstlisting}
# ~/.profile: executed by the command interpreter for login shells.
# This file is not read by bash(1), if ~/.bash_profile or ~/.bash_login
# exists.
# see /usr/share/doc/bash/examples/startup-files for examples.
# the files are located in the bash-doc package.

# the default umask is set in /etc/profile
#umask 022

# if running bash
if [ -n "$BASH_VERSION" ]; then
    # include .bashrc if it exists
    if [ -f "$HOME/.bashrc" ]; then
	. "$HOME/.bashrc"
    fi
fi

# set PATH so it includes user's private bin if it exists
if [ -d "$HOME/bin" ] ; then
    PATH="$HOME/bin:$PATH"
fi
\end{lstlisting}
		\end{subsubsection}

		%Ej 3.1.3
		\begin{subsubsection}{find}
		 Los archivos que comienzan con \textit{vmlinuz} son:\\
		\texttt{\# find -name vmlinuz*}\\
		\texttt{/boot/vmlinuz-2.6.24-24-virtual}\\
		\texttt{/vmlinuz}
		\end{subsubsection}

		%Ej 3.1.4
		\begin{subsubsection}{mkdir}
		 \texttt{mkdir tp}
		\end{subsubsection}

		%Ej 3.1.5
		\begin{subsubsection}{cp}
		 \texttt{cp /etc/passwd tp}
		\end{subsubsection}

		%Ej 3.1.6
		\begin{subsubsection}{chgrp}
		 \texttt{chgrp tp tp/passwd}
		\end{subsubsection}

		%Ej 3.1.7
		\begin{subsubsection}{chown}
		 \texttt{chown tp tp/passwd}
		\end{subsubsection}

		%Ej 3.1.8
		\begin{subsubsection}{chmod}
		 \texttt{chmod 751 tp/passwd}
		\end{subsubsection}

		%Ej 3.1.9
		\begin{subsubsection}{grep}
			\begin{itemize}
					\item \texttt{\$ grep -ni localhost /etc/hosts}\\
					\texttt{1:127.0.0.1  localhost}\\
					\texttt{5:::1  ip6-localhost  ip6-loopback}
					
					\item \texttt{\$ grep -Isrn POSIX /etc/}\\
					\texttt{/etc/init.d/glibc.sh:136:                echo WARNING: POSIX threads library NPTL requires kernel version}\\
					\texttt{/etc/security/limits.conf:35:\#        - msgqueue - max memory used by POSIX message queues (bytes)}
				\end{itemize}
		\end{subsubsection}

		%Ej 3.1.10
		\begin{subsubsection}{passwd}
			\begin{itemize}
					\item contraseña anterior \textit{candado}
					\item contraseña nueva \textit{contraseñasegura}
				\end{itemize}
		\end{subsubsection}

		%Ej 3.1.11
		\begin{subsubsection}{rm}
		 \texttt{rm tp/passwd}
		\end{subsubsection}

		%Ej 3.1.12  --username = tp
		\begin{subsubsection}{ln}
		 	\texttt{ln -T /etc/passwd /tmp/contra1} \\
				\texttt{ln -T /etc/passwd /tmp/contra2} \\
				Con el comando \texttt{ls -l} se puede ver que la cantidad de enlaces al archivo \texttt{/etc/passwd} es 3. Estos enlaces corresponden a los archivos \texttt{/etc/passwd, /tmp/contra1 y /tmp/contra2}.
		\end{subsubsection}
		
		%Ej 3.1.13
		\begin{subsubsection}{mount}
		 	\texttt{mount -r /dev/cdrom} monta el CD-ROM\\
					\texttt{ls /dev/cdrom0} lista el contenido\\
					\texttt{mount} presenta los filesystems montados
		\end{subsubsection}
		
		%Ej 3.1.14
		\begin{subsubsection}{df}		 
			\texttt{\$ df -h}\\
			\texttt{Filesystem            Size  Used Avail Use\% Mounted on}\\
			\texttt{/dev/sda1             494M  410M   59M  88\% /}\\
			\texttt{varrun                189M   36K  189M   1\% /var/run}\\
			\texttt{varlock               189M     0  189M   0\% /var/lock}\\
			\texttt{udev                  189M   40K  189M   1\% /dev}\\
			\texttt{devshm                189M     0  189M   0\% /dev/shm}\\
			\texttt{share                  71G   15G   57G  21\% /media/share}
		\end{subsubsection}
		
		%Ej 3.1.15
		\begin{subsubsection}{ps}
			\texttt{ps -u `whoami`} lista los procesos del usuario\\
			\texttt{echo \$((`ps -u root|wc -l` - 2))} cuenta la cantidad de procesos del sistema
		\end{subsubsection}
		
		%Ej 3.1.16
		\begin{subsubsection}{umount}
			\texttt{umonut /dev/cdrom}
		\end{subsubsection}
		
		%Ej 3.1.17
		\begin{subsubsection}{uptime}
			\texttt{uptime}
		\end{subsubsection}
		
		%Ej 3.1.18
		\begin{subsubsection}{uname}
			Mediante el comando \texttt{uname -snr} podemos saber que la version del sistema operativo es: \texttt{Linux jeos-so 2.6.24-24-Virtual}.
		\end{subsubsection}
	\end{subsection}
	
	
	\begin{subsection}{Comandos extendidos de Unix}
		%Ej 3.2.1
		\begin{subsubsection}{Ejecución automática}
			\begin{itemize}
				\item Agrego al final del archivo \texttt{/etc/bash.bashrc} la ruta del script que imprime el mensaje en pantalla (\texttt{/home/tp/3.2/ej\_3.2.1.a}).
				\item El archivo \texttt{/etc/rc.local} es un script que permite ejecutar otros scripts a nivel de ejecucion 3 definidos por el admistrador. Por defecto esta desactivado. Para que se ejecute el script deseado al momento del inicio basta con agregar al final del archivo \texttt{/etc/rc.local} la ruta del script que imprime el mensaje en pantalla (\texttt{/home/tp/3.2/ej\_3.2.1.b}).
				\item Agrego al final del archivo \texttt{/etc/bash.bash\_logout} la ruta del script que imprime el mensaje en pantalla (\texttt{/home/tp/3.2/ej\_3.2.1.b}).
				\item Agrego el script que imprime el mensaje en pantalla en el directorio \texttt{/etc/init.d} usando el comando \texttt{ln -t /etc/init.d ./3.2/ej\_3.2.1.d}. Luego, para que corra el script al momento del apagado lo agrego al directorio \texttt{/etc/rc0.d} con el siguiente comando: \texttt{sudo ln -sT /etc/init.d/ej\_3.2.1.d /etc/rc0.d/S25ej\_3.2.1.d}.
			\end{itemize}
		\end{subsubsection}

		%Ej 3.2.2
		\begin{subsubsection}{Dispositivos especiales}
			Para montar la imagen de floppy: \texttt{sudo mount -t auto /dev/fd0 /mnt/floppy} \\
			Para montar la imagen iso, primero necesitamos creamos el directorio \texttt{/mnt/iso} con permisos de administrador haciendo \texttt{sudo mkdir /mnt/iso}. Luego, para montar la imagen hacemos \texttt{mount -o loop imagen.iso /mnt/iso}
		\end{subsubsection}

		%Ej 3.2.3
		\begin{subsubsection}{Cambios de hora}
			 Primero guardamos el timestamp del archivo:\\
			\texttt{timestamp=`date -r .bashrc +\%y\%m\%d\%H\%M.\%S`}\\
			luego agregamos el alias:\\
			\texttt{echo ``alias eco=echo'' \textgreater\textgreater .bashrc}\\
			luego seteamos el timestamp al valor anterior:\\
			\texttt{touch .bashrc -t \$timestamp}\\
			\medskip
		
			Para cambiar la hora del sistema:\\
			\texttt{sudo date --set ``25 DEC 2010 20:00:00''}\\
			Si se cambia la hora hacia atrás puede haber archivos con tiempo de modificación en el futuro, y si se modificaran se volvería hacia atrás el tiempo.		
		\end{subsubsection}

		%Ej 3.2.4
		\begin{subsubsection}{Lapsos y tiempos}
			Para ver los tiempos de booteo y los usuarios que accedieron podemos hacer \texttt{last}.
			Se muestran los tiempos exactos en los que sucedió cada evento.
		\end{subsubsection}

		%Ej 3.2.5
		\begin{subsubsection}{Salida estándar y pipes}		
			\begin{enumerate}[1.]
				%Ej 3.2.5.1
				\item \textbf{STDOUT}\\
					\begin{enumerate}[a)]
						\item \texttt{ls -R /etc/ > tp/config}
						\item \texttt{wc -lwc < tp/config}
						\item \texttt{sort /etc/passwd \textgreater\textgreater tp/config}
						\item \texttt{wc -lwc < tp/config}
					\end{enumerate}
				
				%Ej 3.2.5.2
				\item \textbf{Pipes}\\
					\texttt{ls -l /usr/bin/a* | grep apt | wc -lwc}
			\end{enumerate}
		\end{subsubsection}

	\end{subsection}



	
	\begin{subsection}{Scripting}
		%Ej 3.3.1
		\begin{subsubsection}{cron}
		 	Primero creamos el shell script en nuestro home folder. Por ejemplo con\\
			\texttt{echo ``echo Hola! | wall'' > hola.sh}\\
			Luego le damos permisos de ejecucioón con \texttt{chmod +x hola.sh}.\\
			\medskip
			
			Vamos a usar cronjobs para ejecutarlo cada cierto tiempo. Instalamos el paquete \texttt{cron}: \texttt{sudo apt-get install cron}.\\
			Ahora ejecutamos \texttt{crontab -e} y se va a abrir un archivo en el que podemos agregar las entradas correspondientes. Agregamos\\
			\texttt{*/5 * * * * /home/tp/hola.sh}\\
			para que se ejecute cada 5 minutos, todas las horas de todos los dias. Y agregamos\\
			\texttt{7 11 * * * /home/tp/hola.sh}\\
			para que también se ejecute a las 11:07am todos los dias.\\
			\medskip
			
			Ahora podemos ver cada 5 minutos que aparece un mensaje como este:\\
			\texttt{Broadcast message from tp@sisop at 11:10 ...}\\
			\texttt{Hola!}	
		\end{subsubsection}

		%Ej 3.3.2
		\begin{subsubsection}{bash}
			El siguiente script toma una lista con entradas de la forma\\
			\texttt{id usuario [grupo] [home] clave}\\
			(donde \texttt{grupo} y \texttt{home} son opcionales) 
			y agrega y modifica los usuarios acordemente. Debe ser corrido con privilegios de root, por ejemplo:\\
			\texttt{sudo ./upd\_passwd lista}

\begin{lstlisting}
#!/bin/bash
if [ `id -u` -ne 0 ]; then echo "Debe ejecutar el script como root"; exit; fi
if [ "$1" = "" ]; then echo "El primer parametro debe ser un archivo con la lista"; exit; fi
while read id usuario grupo home pass
do
	if [ "$pass" = "" ]; then
		if [ "$home" = "" ]; then #faltan 2 parametros
			pass=$grupo
			grupo=""
		else #falta un parametro
			pass=$home
			if [[ "$grupo" =~ "/" ]]; then
				home=$grupo
				grupo=""
			fi
		fi
	fi
			
	lineaId=$(grep "x:$id" /etc/passwd)
	lineaNombre=$(grep "$usuario:x" /etc/passwd)
	
	if [ "$lineaNombre" = "" -o "$lineaId" = "$lineaNombre" ]
	then
		#creo el grupo si no existia
		if [ "$grupo" != "" ]; then
			realGrupo=$(grep "$grupo:x" /etc/group);
			if [ "$realGrupo" = "" ]; then groupadd $grupo; fi
		fi
		
		if [ "$lineaId" = "" -a "$lineaNombre" = "" ]
		then
			#Usuario nuevo
			useradd $usuario -u $id -g $grupo -d $home
			(echo $pass; sleep 1; echo $pass) | passwd $usuario
		else
			#Modificar usuario
			(echo $pass; sleep 1; echo $pass) | passwd $usuario
			if [ "$home" != "" -a "$grupo" != "" ]
			then usermod -u $id -d $home -g $grupo -m $usuario
			else if [ "$home" != "" ]
				then usermod -u $id -d $home -m $usuario
				else usermod -u $id -m $usuario
				fi
			fi
		fi
	else echo "Error, nombre-id mismatch" 1>&2
	fi
done < $1
\end{lstlisting}
		\end{subsubsection}
	\end{subsection}
	
	
	\begin{subsection}{Ejecución de procesos en background}
			%Ej 3.4.1
			\begin{subsubsection}{loop.c}
		 	\begin{enumerate}[1.]
				%Ej 3.4.1.1
				\item Imprime indefinidamente \texttt{48495051525354555657} en la pantalla.
				%Ej 3.4.1.2
				\item \texttt{./loop >/dev/null \&} redirecciona el output al vacío y corre el proceso en background. No se imprime nada en pantalla pero el proceso está corriendo de fondo. Se devuelve el prompt de la consola al usuario.\\
					\texttt{kill \%1} mata el proceso.
			\end{enumerate}
		\end{subsubsection}
	\end{subsection}
	
	
	
	\begin{subsection}{IPC y Sincronización}
		%Ej 3.5.1
		\begin{subsubsection}{Señales}
\begin{lstlisting}
#include<signal.h>
#include<stdio.h>

void handler(int s){
	printf("SIGINT!\n");
}

int main(){
	signal(SIGINT,handler);
	while(1);
	return 0;
}
\end{lstlisting}
				El proceso no finaliza cuando recibe la señal de interrupción (Ctrl-C). Para finalizar el proceso se puede pararlo con Ctrl-Z y luego matarlo con \texttt{kill \%1}.
			\end{subsubsection}


		%Ej 3.5.2
		\begin{subsubsection}{Pipes}
\begin{lstlisting}
#include <stdio.h>
#include <stdlib.h>

//una funcion que tarda un rato en ejecutarse
void haceralgo(char* quien){ printf("%s entered",quien); fflush(NULL); sleep(rand()%3); printf(" -> %s exiting\n",quien); }

int main(int argc, char *argv[]){
	int pipefd[2];
	pid_t cpid;
	char w='L';
	char r;
	
	//Creo el pipe
	if(pipe(pipefd)==-1) exit(EXIT_FAILURE);
	
	//Inicializo el pipe
	while(write(pipefd[1], &w, 1) != 1);
	
	//Duplico el proceso
	if((cpid = fork())==-1) exit(EXIT_FAILURE);

	if(cpid==0){
		// Child
		while(1){
			while(read(pipefd[0], &r, 1) != 1); //espero el lock
			haceralgo("Child");
			while(write(pipefd[1], &w, 1) != 1); //libero el lock
			sleep(rand()%3);
		}
	}else{
		//Parent
		while(1){
			while(read(pipefd[0], &r, 1) != 1); //espero el lock
			haceralgo("Parent");
			while(write(pipefd[1], &w, 1) != 1); //libero el lock
			sleep(rand()%3);
		}
	}
	wait(NULL); //Espero a los procesos para terminar
	return 0;
}
\end{lstlisting}
			
		\end{subsubsection}


		%Ej 3.5.3
		\begin{subsubsection}{Threads}
				\begin{enumerate}[a.]
					\item
\begin{lstlisting}
#include<stdio.h>
#include<pthread.h>
#include<semaphore.h>

//Defino semaforos para exclusion
sem_t p;
sem_t c;
char buffer;

void* productor(){
	while(1){
		sem_wait(&p); //Esperar mi turno
		printf("Produciendo.."); fflush(NULL); sleep(rand()%3);
		buffer=rand()/100%26+65; //Lleno el buffer
		printf("producido %c\n",buffer);
		sem_post(&c); //Habilitar consumo
		sleep(rand()%3);
	}
}

void* consumidor(){
	while(1){
		sem_wait(&c); //Esperar mi turno
		printf("Consumiendo.."); fflush(NULL);
		sleep(rand()%3); printf("consumido %c\n",buffer); //Leo el buffer
		sem_post(&p); //Habilitar produccion
		sleep(rand()%3);
	}
}

int main(){
	//defino los threads
	pthread_t t_productor;
	pthread_t t_consumidor;
	//inicializo los semaforos
	sem_init(&p,0,1); //produccion habilitada
	sem_init(&c,0,0); //consumo deshabilitado
	
	//crear los threads
	pthread_create(&t_productor, NULL, productor, NULL);
	pthread_create(&t_consumidor, NULL, consumidor, NULL);
	//esperar a que terminen
	pthread_join(t_productor,NULL);
	pthread_join(t_consumidor,NULL);
	return 0;
}
\end{lstlisting}

				\item
\begin{lstlisting}
#include<stdio.h>
#include<pthread.h>

#define DIST 10
pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;
int dist []={0,DIST}; //posicion de los corredores
int direccion []={1,-1}; //direccion de movimiento de los corredores

void* corredor(void* num){
	int c=(int)num;
	while(1){
		sleep(rand()%4); //espero
		pthread_mutex_lock(&mutex);
		if(dist[0]<dist[1]){
			dist[c-1]+=direccion[c-1]; //avanzo
			printf("corredor %d avanza a %d\n",c,dist[c-1]);
			pthread_mutex_unlock(&mutex);
		}else{
			pthread_mutex_unlock(&mutex);
			return;
		}
	}
}

int main(){
	pthread_t c1;
	pthread_t c2;
	
	//crear los threads
	pthread_create(&c1, NULL, corredor, (void*)1);
	pthread_create(&c2, NULL, corredor, (void*)2);
	//esperar a que terminen
	pthread_join(c1,NULL);
	pthread_join(c2,NULL);
	printf("Punto de encuentro: %d\nDistancia recorrida por 1: %d\nDistancia recorrida por 2: %d\nGanador: %s\n", dist[0],dist[0],DIST-dist[1],dist[0]>=DIST/2?(dist[0]==DIST/2?"Empate!":"1"):"2");
	return 0;
}
\end{lstlisting}
			
			\end{enumerate}
		\end{subsubsection}
	\end{subsection}



	
	\begin{subsection}{El Kernel Linux}
		%Ej 3.6.1
		\begin{subsubsection}{Funcionamiento del kernel Linux}
			\begin{enumerate}[1.]
				\item \textbf{Administración de Procesador}\\ El administrador de procesos de Linux es una parte importante de este sistema operativo que se encuentra encargado de realizar algunas tareas fundamentales en relación a los procesos, como puede ser permitirles acceso al CPU, realizar fork de sí mismos, enviar mensajes (usuario).  Cada proceso tiene una única identificación llamada pid (process id), que permite identificar a cada uno de ellos en la tabla de procesos.

				También es el encargado de manejar el reloj de hardware, recibir y desviar interrupciones a su correspondiente subsistema, así como también liberar recursos cuando un programa los haya dejado de utilizar.  A su vez el sistema operativo posee un reloj interno que se inicia cada 10ms con el fin de realizar una reasignación de procesos, permitiendo de esta forma ejecutar una política de Round Robin y medir la cantidad de ticks por proceso. Pero no todos los procesos tienen la misma proridad, de hecho obtener la siguiente tarea a ejecutar, no depende de la cantidad de tareas, sino de la cantidad de prioridades que uno está utilizando, para que de esta forma las operaciones del administrador de procesos se vean acotadas. Además utiliza una política de desalojo en caso de necesitar ejecutar una tarea de mayor prioridad, la que se está ejecutando en ese momento pasa a ser relegada y encolada en su correspondiente lista, pero esto no implica inanición de procesos, pues tiene un sistema de puntuaciones y penalizaciones para procesos que equiparan esta situación, a esta metodología se la llama priorización dinámica.

				Asimismo tiene la capacidad de soportar módulos cargados dinámicamente.  En este contexto, módulo se refiere a un controlador de un dispositivo o servicio que puede cargarse o descargarse cuando el usuario o algún dispositivo lo solicitan.  Los módulos que se distribuyen con en el kernel están ubicados en el directorio \texttt{/lib/modules/version}, donde version es la versión de su kernel , con la extensión .o organizados en directorios que indican el tipo de dispositivo o el propósito, por ejemplo fs - sistema de archivos, net - protocolos y hardware para redes.

				\bigskip			
			
				\item \textbf{Administración de Memoria}\\ La administración de memoria de Linux es otro elemento fundamental del sistema operativo y utiliza mecanismos de administración de memoria paginada por demanda. Para la paginación utiliza tres niveles de tablas de páginas. Cada nivel contiene el número de página correspondiente al siguiente nivel en las tablas. El encargado de obtener las direcciones es el procesador, al cual se le ofrecen estas tablas para poder realizar el cálculo. Según la plataforma en la que se encuentre corriendo el Linux, deben existir herramientas para que el kernel pueda trabajar sin la necesidad de conocer la arquitectura, permitiendo de esta forma una funcionalidad sobre una alta gama de procesadores. 

				La administración de memoria es la encargada de ubicar las páginas físicas de memoria, por ejemplo al momento de cargar un programa, esta reserva la cantidad de páginas que en ese momento considera necesarias para toda la ejecución del programa, liberándolas recién cuando este termine. El algoritmo utilizado para este proceso consiste en buscar en un arreglo de áreas de memoria  libre, el tamaño de memoria solicitado, de no encontrase uno que satisfaga exactamente la petición, se busca en bloques más grandes hasta encontrar un libre y particionandolo, quedándonos con el bloque necesario. Es aquí donde surge una de las partes más problemáticas del sistema operativo, pues la adquisición de bloques de páginas generalmente fragmenta la memoria cuando se dividen grandes bloques de memoria  en partes más pequeñas con el fin de satisfacer algún pedido.  Una de las soluciones que se encontró a este punto es al momento de liberar las páginas libres de manera tal que queden bloques lo más grande posibles, y a su vez se chequea que los bloques adyacentes a este se encuentren también libres, para que de ser posible se unifiquen proporcionando una partición de memoria más grande.

				Como la memoria fásica es escasa, el sistema operativo utiliza también memoria de tipo virtual. Este tipo de memoria se administra bajo el mecanismo de mapeo de memoria que consiste en lo siguiente: cuando un programa se encuentra ejecutándose  tiene su contenido en espacio de direcciones virtuales, pero estas no son traídas inmediatamente, sino que son linkeadas a la memoria virtual del proceso y es recién cargado a memoria física al momento de ser referenciada.  El programa únicamente puede ser ejecutado si la imagen del ejecutable ha sido linkeada por completo en direcciones virtuales. Como mencionamos anteriormente, a medida que se ejecuta va trayendo direcciones virtuales que pueden encontrarse o no en memoria física, en caso de no encontrarse provocará un page fault. En el momento del page fault el kernel debe buscar a qué área corresponde la dirección virtual que ocasionó el problema, para luego cargar la información en memoria física. Este proceso debe realizarse de manera muy veloz, ya que es común que un programa presente page faults durante su ejecución y el tener una estructura lenta de búsqueda podría ocasionar ejecuciones muy lentas de los programas, es por esto que se utilizan estructuras del tipo árboles avl. En caso de encontrarla la carga en memoria y continúa su ejecución, aunque también puede no encontrarla o no tener permisos para esa página. Si el administrador de memoria detecta un acceso no permitido (a la memoria), notifica al proceso con una señal. Si el proceso no sabe cómo manejar esta señal, entonces, es finalizado. Para ello Linux debe diferenciar entre qué páginas se encuentran en la partición swap (espacio del disco usado para alojar las páginas que son desalojadas de memoria física) y cuáles no han sido cargadas aún desde el archivo original del ejecutable, apoyándose en la entrada de las tablas de páginas. Si la entrada no está vacía, pero es inválida, entonces hay que ir a buscar a la partición swap, caso contrario debe traerse desde el archivo original.

				El proceso de liberación de memoria física está encargado por un demonio llamado kswapd, de tipo kernel thread, por lo que no tiene memoria virtual.  Estos son ejecutados directamente sobre la memoria física en modo kernel guardando las páginas en la partición swap y asegurando que haya suficientes páginas libres para un correcto funcionamiento de la administración de memoria. Para la realización de este proceso, las páginas desalojadas son seleccionadas utilizando un algoritmo llamado envejecimiento, el cual consiste en aumentar tres años la edad de cada página cada vez que es referenciada (tope de veinte años), mientras que cada vez que el demonio revisa el valor lo decremento en un año, hasta llegar a la edad cero, donde intentará liberar la página.

				En definitiva la administración de memoria permite manejar más memoria de la que se tiene, proteger la memoria asignada a  un proceso y permitirle compartirla con otros, y realizar mapeos a memoria virtual entre sus principales características.

				\bigskip

				\item \textbf{Sistema de Archivos}\\ El sistema de archivos utilizado por esta versión de kernel es ext3, que es un sistema de archivos con registro por diario (journaling). Es el sistema de archivo más usado en distribuciones Linux, aunque en la actualidad está siendo remplazado por su sucesor, ext4.
				La principal diferencia con ext2 es el registro por diario. Un sistema de archivos ext3 puede ser montado y usado como un sistema de archivos ext2. Otra diferencia importante es que ext3 utiliza un árbol binario balanceado (árbol AVL) e incorpora el asignador de bloques de disco Orlov.

				Entre las principales ventajas está permitir actualizar de ext2 a ext3 sin perder los datos almacenados ni tener que formatear el disco. Tiene un menor consumo de CPU y está considerado más seguro que otros sistemas de ficheros en Linux dada su relativa sencillez y su mayor tiempo de prueba.
				El sistema de archivo ext3 agrega a ext2 lo siguiente:
				\begin{itemize}
				\item Registro por diario.
				\item Índices en árbol para directorios que ocupan múltiples bloques.
				\item Crecimiento en línea.
				\end{itemize}

				En renferencia al tamaño, ext3 tiene dos límites de distintos, uno para archivos y otro para el tamaño del sistema de archivos entero. El límite del tamaño del sistema de archivos es es 231-1.

				Otra de las ventajas son los tres niveles posibles de registros diario o journaling:
				\begin{itemize}
				\item Diario (riesgo bajo): Los metadatos y los ficheros de contenido son copiados al diario antes de ser llevados al sistema de archivos principal. Como el diario está en el disco continuamente puede mejorar el rendimiento en ciertas ocasiones. En otras ocasiones el rendimiento es peor porque los datos deben ser escritos dos veces, una al diario y otra a la parte principal del sistema de archivos.
				\item Pedido (riesgo medio): Solo los metadatos son registrados en el diario, los contenidos no, pero está asegurado que el contenido del archivo es escrito en el disco antes de que el metadato asociado se marque como transcrito en el diario. Es el sistema por defecto en la mayoría de las distribuciones de Linux. Si hay un bajón de tensión o kernel Panic cuando el fichero se está escribiendo o está empezando, el diario indicará que el nuevo archivo o el intento no ha sido pasado, por lo que sera purgado por el proceso de limpiado
				\item Reescritura (riesgo alto): Solo los metadatos son registrados en el diario, el contenido de los archivos no. Los contenidos pueden estar escritos antes o después de que el diario se actualice. Como resultado, los archivos modificados correctamente antes de una ruptura pueden volverse corruptos. Por ejemplo, un archivo pendiente de ser marcado en el diario como mayor de lo que actualmente es, convirtiendo en basura al final de la comprobación. Las versiones antiguas de los archivos pueden aparecer inesperadamente después de una recuperación de diario. La carencia de sincronización entre los datos y el diario es rápidamente subsanada en muchos casos. JFS usa este nivel de journaling, pero se asegura de que cualquier basura es borrada al reiniciar
				\end{itemize}

				Aunque así como presenta ventajas también existen algunas desventajas en cuanto a la funcionaldad. Como ext3 está hecho para ser compatible con ext2, la mayoría de las estructuras del archivación son similares a las del ext2. Por ello, ext3 carece de muchas características de los diseños más recientes como las extensiones, la localización dinámica de los inodos, y la sublocalización de los bloques. Hay un límite de 31998 subdirectorios por cada directorio, que se derivan de su límite de 32 links por inodo. Ext3, como la mayoría de los sistemas de archivos actuales de Linux, no puede ser chequeado por el fsck mientras el sistema de archivos está montado para la escritura. Si se intenta chequear un sistema de ficheros que está montado puede detectar falsos errores donde los datos no han sido volcados al disco todavía, y corromper el sistema de archivos al intentar arreglar esos errores.

				Otro punto débil de ext3 es la fragmentación, pues no hay herramienta de desfragmentación online para ext3 que funcione en nivel del sistema de archivos. Existe un desfragmentador offline para ext2, e2defrag, pero requiere que el sistema de archivos ext3 sea reconvertido a ext2 antes de iniciarse. Pero dependiendo de los bits encendidos en el sistema, e2defrag puede destruir datos. No sabe como tratar la mayoría de las nuevas características de ext3. Hay herramientas de usuario para desfragmentar como Shake y Defrag. Shake trabaja localizando para todo el archivo como una operación, lo que generalmente causa que el localizador encuentre espacio continuo en el disco. También intenta escribir archivos usados al mismo tiempo que otros. Defrag trabaja copiando cada archivo sobre sí mismo. De todas formas solo funcionan si el sistema de archivos esta razonablemente vacío. No existe una verdadera herramienta de desfragmentacion para ext3. Como se viene diciendo, la guía de administración de Linux dice: "Los modernos sistemas de archivos de Linux mantienen la fragmentación al mínimo manteniendo los bloques de un archivo juntos, aunque no puedan ser guardados en sectores consecutivos. Algunos sistemas de archivos, como ext3, localizan efectivamente los bloques libres más cercanos a otros en el archivo. Por ello no es necesario preocuparse por la fragmentación en un sistema de Linux" Mientras ext3 es más resistente a la fragmentacián que Fat, nada evita que los sistemas ext3 se puedan fragmentar con el tiempo. Consecuentemente el sucesor de ext3, ext4, incluye una utilidad de desfragmentación y soporte para extensiones (regiones contiguas del fichero).

				También presenta flaquezas en cuanto a la compresión y la comprobación de archivos en el diario. Para el primer punto no existe versiones oficiales para tratarlo, existen algunos parches, pero todos de origen extraoficial y no implementa journaling. Respect a la comprobación de archivos ext3 no hace la suma de verificación cuando está escribiendo en el diario. Si no está habilitado como una opción de montaje, y si el hardware está escribiendo fuera de orden, se corre el riesgo de una corrupción muy amplia del sistema de archivos en caso de que haya un fallo repentino del hardware.
				
			\end{enumerate}


			
			\end{subsubsection}
		%Ej 3.6.2
			\begin{subsubsection}{Módulos de kernel}
				El kernel de Linux permite ser ampliado en runtime con módulos. Los módulos son objetos de código compilado
				que pueden ser insertados en runtime al kernel, siendo linkeados contra el kernel al momento de ser insertados. De
				esta manera puede ampliarse la funcionalidad del kernel en runtime, sin tener que incluir todo el código en el binario
				original.
			\end{subsubsection}
			
		%Ej 3.6.3
			\begin{subsubsection}{Compilando un módulo de kernel}
		 	\end{subsubsection}
			
		%Ej 3.6.4
			%\begin{subsubsection}{}
			
			%\end{subsubsection}
		%Ej 3.6.5
			%\begin{subsubsection}{}
			%\end{subsubsection}
		
			
			\setcounter{subsubsection}{5}
		%Ej 3.6.6
			\begin{subsubsection}{Un módulo propio}
				Este módulo crea una entrada en \texttt{/proc} que podemos escribir para modificar el estado de los leds.\\
				para compilar: \texttt{make}\\
				para cargar el módulo: \texttt{insmod leds.ko}\\
				para modificar el estado de los leds: \texttt{echo 111 > /proc/theleds}\\
				(donde cada bit de \texttt{111} representa el estado del respectivo led)\\
				para bajar el módulo: \texttt{rmmod leds.ko}\\
			
				\bigskip
				{\Large \texttt{leds.c}}
			
\begin{lstlisting}
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/proc_fs.h>
#include <asm/uaccess.h>
#include <linux/kd.h>
#include <linux/tty.h>
#include <linux/vt_kern.h>
#include <linux/console_struct.h>

#define NOMBRE "theleds"
static struct proc_dir_entry *procentry;
int bin2dec(char*);
char buffer[4];
int n;

//Funcion que se invoca cuando se escribe la entrada en /proc
int onwrite( struct file *filp, const char __user *buff, unsigned long len, void *data ){
	//copio los primeros 3 bytes de la entrada
	copy_from_user(buffer,buff,3);buffer[3]=0;
	n=bin2dec(buffer); //Convierto de binario a entero
	printk(KERN_ALERT "oi! %d\n",n);
	//llamada a la funcion ioctl para modificar el estado de los leds
	(vc_cons[fg_console].d->vc_tty->driver->ops->ioctl) (vc_cons[fg_console].d->vc_tty, NULL, KDSETLED, n);
	return len;
}

//Funcion que se invoca al cargar el modulo
static int __init leds_init(void){
	printk(KERN_INFO "leds loaded.\n");
	//creo la entrada en /proc
	procentry=create_proc_entry( NOMBRE, 0666, NULL );
	//callback cuando ocurre escritura
	procentry->write_proc=onwrite;
	return 0;
}

static void __exit leds_exit(void){
	//elimino la entrada en /proc
	remove_proc_entry( NOMBRE, NULL );
	printk(KERN_INFO "leds unloaded.\n");
	return;
}

MODULE_LICENSE("GPL");
module_init( leds_init );
module_exit( leds_exit );

int bin2dec(char *bin){
	//funcion que convierte un string binario a un entero
	int k,sum=0,len=strlen(bin)-1;
	for(k=0;k<=len;k++) sum+=(bin[k]-'0')*(1<<(len-k));
	return sum;
}
\end{lstlisting}

			\bigskip
			{\Large \texttt{Makefile}}
\begin{lstlisting}
obj-m=leds.o

all:
	make -C /lib/modules/`uname -r`/build M=`pwd` modules
clean:
	make -C /lib/modules/`uname -r`/build M=`pwd` clean
\end{lstlisting}
			
			\end{subsubsection}
			
			
		%Ej 3.6.7
			%\begin{subsubsection}{}
			%\end{subsubsection}
			
	\end{subsection}
	
	
	

	\begin{subsection}{Temas del sistema operativo}
			%Ej 3.7.1
			\begin{subsubsection}{Comunicación}
				Establecimos comunicación entre el client y el host de dos formas:
				\begin{itemize}
					\item \textbf{netcat}\\
					Primero conectamos el cliente a dhcp con \texttt{sudo dhclient}. El host nos asigna una dirección de IP.\\
					Podemos ver la dirección asignada con \texttt{ifconfig}. En nuestro caso nos conectamos a \texttt{10.0.2.2} con la IP \texttt{10.0.2.15}.\\
					Luego en el host abrimos un puerto para escuchar y volcamos la salida en un archivo: \texttt{nc -l 1234 >archivo}.\\
					En el cliente mandamos el archivo por ese puerto a la IP del host: \texttt{cat archivo | nc 10.0.2.15 1234}\\
					Cuando el host recibe el \texttt{EOF} cierra la conexión y el archivo queda almacenado.
				
					\item \textbf{Guest additions}\\
					La otra forma es instalando los guest additions de VirtualBox en el cliente (\textit{Devices\guilsinglright Install Guest Additions...}).
					Luego montamos el cdrom (como indicado en \textbf{3.1.13}) e instalamos con \texttt{sudo ./VBoxLinuxAdditions-x86.run}.\\
					En \textit{Devices\guilsinglright Shared Folders...} podemos asignar una carpeta compartida del host que luego tenemos que montar en el cliente.\\
					Se puede montar con \texttt{sudo mount -t vboxsf share /media/share}, pero para hacerlo permanente tenemos que agregar una entrada en \texttt{/etc/fstab} como la siguiente:\\
					\texttt{share   /media/share    vboxsf    defaults    0    0}\\
					En \texttt{/media/share} se encuentran los archivos compartidos y se puede leer y escribir.
				\end{itemize}
			\end{subsubsection}
			
			
		%Ej 3.7.2
			\begin{subsubsection}{File system}
				Hard link es una referencia o puntero a un archivo (al dato físico) en un sistema de archivos.

				El nombre asociado a un archivo es simplemente una etiqueta almacenada en una estructura de directorio que referencia el sistema operativo al sistema de archivos. Por lo cual, más de un nombre puede ser asociado al mismo archivo. Cuando se accede a través de diferentes nombres, cualquier cambio hecho afectará el mismo archivo. Los enlaces duros sólo pueden referenciar datos que existen en el mismo sistema de archivos. En la mayoría de los sistemas de archivos, todos los archivos son hard links.

				Aunque se llamen de distinta forma, tanto los hard links como el archivo original (enlace original) ofrecen la misma funcionalidad. Al modificar los datos apuntados por cualquiera de ellos, se cambian los datos reales almacenados en disco, quedando modificados para todos por igual. Al crearlos, debido a su naturaleza, los hard links sólo pueden apuntar a datos que estén en el mismo sistema de archivos que el archivo (enlace) a partir del cual se creen, al ser en realidad una copia de la misma referencia a datos físicos pero apuntada por otra etiqueta.

				Cada hard link aplica unos permisos de acceso a los datos referenciados. La creación de hard links adicionales permite crear enlaces con distintos permisos o propietarios para acceder a los mismos datos. De esta forma, por ejemplo, un enlace puede permitir acceso de escritura, mientras que otro ofrezca sólo de lectura, pudiéndose crear distintas combinaciones para distintos grupos o usuarios. Asimismo, al ser indistinguibles de los archivos, se pueden utilizar hard links para ofrecer acceso a datos desde entornos chroot sin necesidad de duplicar los datos en disco.

				El proceso de eliminación de un enlace, desvincula un nombre de los datos reales. Los datos todavía estarán accesibles mientras quede algún enlace. Cuando se elimina el último hard link, el espacio que ocupaban los datos se considera disponible. Existe un procedimiento de recuperación de archivos borrados, que permite la reconstrucción de un enlace a datos que ya no estén asociados con un nombre. Sin embargo este proceso no está disponible en todos los sistemas y a menudo no es seguro que funcione.
			\end{subsubsection}


		%Ej 3.7.3
			\begin{subsubsection}{Prioridades}
				A partir del binario ejecutable \texttt{loop}, generamos 3 versiones y las ejecutamos:\\
				\texttt{cp loop loop1;cp loop loop2;cp loop loop2}\\
				\texttt{./loop1 > /dev/null \& ./loop2 > /dev/null \& ./loop3 > /dev/null \&}\\
				Ahora podemos ver los procesos en ejecución y su PID con \texttt{ps}.\\
			
				Para hacer que el \texttt{loop3} ejecute más rápido le damos más prioridad:\\
				\texttt{sudo renice -20 3898} (donde 3898 es el PID del proceso loop3).\\
				Las prioridades van desde -20 a 20, siendo -20 la de mayor prioridad.\\
			
				Luego de un tiempo observamos el estado de los procesos (\texttt{ps -l}) y vemos que el loop3 ejecuto mucho más tiempo a pesar de haber sido ejecutadas al mismo tiempo:\\
				\texttt{F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD}\\
				\texttt{4 S  1000  3886  3885  0  80   0 -  1167 -      tty1     00:00:00 bash}\\
				\texttt{0 R  1000  3942  3886  5  80   0 -   391 -      tty1     00:00:04 loop1}\\
				\texttt{0 R  1000  3943  3886  5  80   0 -   391 -      tty1     00:00:04 loop2}\\
				\texttt{0 R  1000  3944  3886 87  60 -20 -   391 -      tty1     00:01:02 loop3}\\
				\texttt{0 R  1000  3958  3886  2  80   0 -   607 -      tty1     00:00:00 ps}\\			
			\end{subsubsection}


		%Ej 3.7.4
			\begin{subsubsection}{Parámetros del Kernel}
				\begin{itemize}
					\item Para ver la cantidad de memoria del sistema y el actual uso de la misma podemos usar el comando \texttt{free}.\\
					(con \texttt{free -m} se muestran los valores en megabytes).
				
					\item Para que el sistema use menor cantidad de memoria RAM podemos agregar el parámetro del kernel \texttt{mem}.\\
					En el GRUB editamos la entrada del kernel y agregamos el parámetro \texttt{mem=64M} y booteamos.
					Ahora el sistema está usando menos memoria, podemos comprobarlo con \texttt{free -m}.
				\end{itemize}
			\end{subsubsection}
			
			
		%Ej 3.7.5
			\begin{subsubsection}{Administración de memoria}
				El tamaño del swap que estamos utilizando se puede ver con \texttt{free -m}. En la columna total se indica el tamaño del swap, en este caso es de 86MB.\\
			
				Para ampliar el swap mediante un archivo:\\
				Creamos el archivo: \texttt{sudo dd if=/dev/zero of=/media/swap2 bs=2048 count=2048}\\
				Lo convertimos a un swap: \texttt{sudo mkswap /media/swap2}\\
				Lo montamos como swap: \texttt{sudo swapon /media/swap2}\\
			
				Para hacerlo persistente debemos agregar una entrada a \texttt{/etc/fstab}:\\
				\texttt{/media/swap2 swap swap defaults 0 0}
			\end{subsubsection}
			
			
		%Ej 3.7.6
			\begin{subsubsection}{Otro módulo de kernel}
				Este módulo impide la creación de nuevos directorios mediante una intercepción al system\_call.\\
				Para ello modifica la \texttt{sys\_call\_table} cambiando la entrada del mkdir por una funcion propia.
				Desde la versión 2.6 del kernel la \texttt{sys\_call\_table} no es exportada y no tiene permisos de escritura,
				por eso la direccion esta hardocdeada y hay que modificar los permisos de la página.\\
			
				Ejemplo:\\
				\texttt{\$ sudo insmod mkdirhack.ko}\\
				\texttt{\$ mkdir hola}\\
				\texttt{Thou shalt not make dirs!}\\
				\texttt{\$ sudo rmmod mkdirhack.ko}\\
				\texttt{\$ mkdir hola}\\
			
\begin{lstlisting}
#include<linux/kernel.h>
#include<linux/module.h>
#include<linux/moduleparam.h>
#include<linux/unistd.h>
#include<linux/sched.h>
#include<asm/uaccess.h>
#include<asm/cacheflush.h>

#define DIR_SYS_CALL_TABLE 0xc0318500
void **sys_call_table = (void *) DIR_SYS_CALL_TABLE;
asmlinkage int (*sys_call_orig) (const char *pathname);
struct page *pg;
pgprot_t prot;

int hacked_mkdir(const char *path){
	printk(KERN_ALERT "Thou shalt not make dirs!\n");
	return 0;
}

static int __init init_mkdirhack(void){
	//guardo la syscall original
	sys_call_orig = sys_call_table[__NR_mkdir];
	//modifico los permisos de escritura de la pagina
	pg = virt_to_page( DIR_SYS_CALL_TABLE );
	prot.pgprot = VM_READ | VM_WRITE | VM_EXEC;
	change_page_attr(pg, 1, prot);
	//reemplazo la syscall por mi funcion
	sys_call_table[__NR_mkdir] = hacked_mkdir;
	return 0;
}

static void __exit exit_mkdirhack(void){
	sys_call_table[__NR_mkdir] = sys_call_orig;
}

MODULE_LICENSE("GPL");
module_init(init_mkdirhack);
module_exit(exit_mkdirhack);
\end{lstlisting}
			
			\end{subsubsection}
			
			
			
		%Ej 3.7.7
			\begin{subsubsection}{Y otro más}
				Este módulo crea un device en \texttt{/dev/probablidad} que devuelve letras aleatorias \texttt{[A-Z]}.\\
				Además crea una entrada en \texttt{/proc/probabilidad} que contiene la cantidad de lecturas realizadas y al cual se le puede escribir un seed para la aleatorización del device.\\
			
				Ejemplo de lectura (ojo, el resultado es infinito): \texttt{sudo cat /dev/probabilidad}\\
				Otro ejemplo: \texttt{sudo dd if=/dev/probabilidad of=letras bs=1024 count=25}\\
				Para obtener la cantidad de lecturas: \texttt{cat /proc/probabilidad}\\
				Para establecer un seed: \texttt{echo 5 > /proc/probabilidad}\\

\begin{lstlisting}
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/proc_fs.h>
#include <linux/device.h>
#include <linux/random.h>

#define PROCENTRY "probabilidad"
#define DEVICE "probabilidad"
static int cant_read=0; //cantidad de lecturas realizadas
static struct proc_dir_entry *procentry;
static int major;
static struct class *class;
static struct device *device;
static struct file_operations fops={
	.read = device_read
}

static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset);

//Funcion que se invoca cuando se escribe la entrada en /proc
int onwrite( struct file *filp, const char __user *buff, unsigned long len, void *data ){
	srandom32(buff[0]-'0');
	return len;
}
//Funcion que se invoca cuando se lee la entrada en /proc
int onread(char *buffer, char **buffer_location, off_t offset, int buffer_length, int *eof, void *data){
	if(offset>0) return 0;
	else return sprintf(buffer,"%d\n",cant_read);
}
//Funcion que se invoca cuando se lee el device
static ssize_t device_read(struct file *filp, char *buffer, size_t length, loff_t *offset){
	buffer[0] = ((char)(random32()%26))+'A'; //una letra random
	cant_read++;
	return 1;
}

//Funcion que se invoca al cargar el modulo
static int __init proba_init(void){
	printk(KERN_INFO "proba loaded.\n");
	//creo la entrada en /proc
	procentry=create_proc_entry( PROCENTRY, 0666, NULL );
	procentry->write_proc=onwrite;//callback cuando ocurre escritura
	procentry->read_proc=onread;//callback cuando ocurre lectura
	//creo el device en /dev
	major = register_chrdev(0, DEVICE, &fops);
	class = class_create(THIS_MODULE,"probabilidad");
	device= device_create(class, NULL, MKDEV(major,0),NULL,DEVICE);
	return 0;
}

static void __exit proba_exit(void){
	//elimino la entrada en /proc
	remove_proc_entry( PROCENTRY, NULL );
	//elimino el device
	device_destroy(class,MKDEV(major,0));
	class_unregister(class);
	class_destroy(class);
	unregister_chrdev(major, DEVICE);
	printk(KERN_INFO "proba unloaded.\n");
	return;
}

MODULE_LICENSE("GPL");
module_init( proba_init );
module_exit( proba_exit );
\end{lstlisting}

			\end{subsubsection}
			
			
			
		%Ej 3.7.8
		\begin{subsubsection}{Administración de memoria y scheduling en windows}

		El administrador de tareas de Windows fue variando a medida que pasaron los años. Al comienzo ni siquiera existía un scheduler, luego se fue consolidando hasta que con la aparición de la technología NT, se implementó una multicola con diferentes prioridades, en total eran treinta y dos, las cuales estaban divididas una mitad para los procesos de prioridad media y la otra mitad para procesos de prioridad alta.
		Este administrador utiliza una política de round robin para el tratamiento de los procesos, dándole un quantum más alto a aquellos procesos que tengan mayor prioridad. Esto lo implementa sobre un arreglo de listas, donde en cada posición se encuentra el comienzo de cada una de estas listas. De la manera que se encuentra planteado este administrador no es util para la implementación de sistemas de tiempo real, ya que no hay ninguna de las prioridades del sistema que permita hacer que alguno de los procesos se convierta en un proceso de tiempo real. 
		A su vez como este scheduler le da más prioridad a los procesos que utilizan dispositivos de entrada y salida o a aquelos que son de tipo interactivo, el kernel se ve encargado de actualizar constantemente las prioridades de estos procesos. 
		Luego con el ingreso de Vista al mercado, se incorporaron algunas mejoras para este scheduler, más que nada con el objetivo de mejorar la rotación y asignación de prioridades del sistema. Uno de los cambios más importantes fue la posibilidad de asignar el quantum en función de los ciclos de cpu en lugar de tiempos, ganando de esta forma una comportamiento más equitativo de los tiempos de procesador y más predecible, pues ciclos es una medida más precisa que además no tomaba en cuenta los ciclos que utilizó el sistema operativo o los ciclos peridos por alguna interrupción.

		Por otra parte la administración de memoria fue un punto más cambiante en el sistema operativo de Microsoft, pues a medida que Intel iba sacando modificaciones en sus procesadores, como Windows utilizaba esta arquitectura para el desarrollo de sus productos, la administración de memoria iba adaptando nuevas mejoras a medida que aparecían nuevas funcionalidades.
		Tomando nuevamente como punto de partida la technología NT, nos encontramos con un espacio de direccionamiento plano, no segmentado, que hace uso de los mecanismos de protección del procesador, evitando así que un proceso pueda interferir en el espacio de memoria del otro, pues cada uno de ellos tenía asignado un espacio diferente de la memoria. Con un espacio de direccionamiento de 4Gb, la mitad más significativa se encontraba asignada al kernel, mientras que la otra mitad a procesos del usuario. Pero a pesar de esto el espacio de direcciones no se encuentra separado para cada proceso, por lo que la imagen del kernel es comun a todos, aunque obviamente tenga restricciones de permisos para el usuario. Se pueden compartir espacios de la memoria entre procesos, pero de manera implicita, es decir que varios procesos deben mapear los mismos archivos en sus espacios de direcciones para poder compartir entre ellos.  
		Para el manejo de memoria virtual, utiliza varias estructuras de tablas de páginas provistas por el procesador. En los casos que ocurra page fault, existe un handler que maneja el fault, trayendo a memoria física la página faltante. Al igual que linux la fuente de obtención de la página varia dependiendo de la misma, pues si es código ejecutable o dll se obtiene d eun archivo ejecutable o dll, mientras que si es de datos se obtiene del a memoria swap. 
		Para realizar un manejo de la memoria virtual de manera eficiente el sistema operativo guarda en una estructura de datos llamada Page Frame DataBase, la cual también contiene una lista fifo que es utilizada para ver cual es la página que puede liberar a la hora de necesitar realizar este proceso. Previo a la liberación de la página, se verifica que esta no haya sido modificada, en caso de estarlo, la guarda en memoria física para recuperarla en el momento que sea necesario.
		Si la página no esta siendo compartida, la Page Frame Database contiene un puntero a la Page Table Entry para que el sistema pueda marcar dicha entrada como inválida si es que decide desalojar la página. Contrariamente, si la página esta siendo compartida, la PFD apunta a la entrada llamada PROTOPTE, junto con un contador de referencias. Sólo cuando las referencias han llegado a 0 es que se puede desalojar la página. En general la page frame database mantiene el estado de todas las páginas presentes en memoria física.
		A su vez, cada vez que un proceso hace uso de un bloque de memoria, el sistema operativo debe chequear que el bloque se encuentre libre en el espacio de direcciones virtuales y actualizar aquellas tablas que sean necesarias, en la tabla de páginas del proceso. Como estas páginas pueden ser removidas, el sistema operativo tiene un ABB con la información de la memoria virtual que es usada por cada proceso. 
			
		\end{subsubsection}
	\end{subsection}

\end{section}

\begin{section}{Referencias}
	\begin{enumerate}
		\item \label{ref:ubuntu-kernel} \texttt{http://doc.ubuntu-es.org/Kernel}\\ Introducción al kernel en ubuntu-es
		\item \label{ref:ubuntu-fs} \texttt{http://es.wikipedia.org/wiki/Ext3}\\ Wikipedia ext3 filesystem
		\item \label{ref:wiki-hardlink} \texttt{http://es.wikipedia.org/wiki/Enlace\_duro}\\ Wikipedia Hard-link
		\item \label{ref:ibm-syscall} \texttt{http://www.ibm.com/developerworks/linux/library/l-system-calls/}\\ Kernel command using Linux system calls
		\item \label{ref:ibm-proc} \texttt{http://www.ibm.com/developerworks/linux/library/l-proc.html}\\ Access the Linux kernel using the /proc filesystem
		\item \label{ref:lkm-guide} \texttt{http://www.linuxtopia.org/online\_books/Linux\_Kernel\_Module\_Programming\_Guide/} \\ The Linux Kernel Module Programming Guide
		\item \label{ref:journal-syscall} \texttt{http://www.linuxjournal.com/article/4378} \\ Loadable Kernel Module Programming and System Call Interception
		\item \label{ref:orly-lkm} \texttt{http://commons.oreilly.com/wiki/index.php/Network\_Security\_Tools/\\Modifying\_and\_Hacking\_Security\_Tools/Fun\_with\_Linux\_Kernel\_Modules}\\ Fun with Linux Kernel Modules
		\item \label{ref:gnu-bash} \texttt{http://www.gnu.org/software/bash/manual/bashref.html}\\ Bash reference Manual
	\end{enumerate}
\end{section}
\end{document}
